package de.zainodis.kitchengnome.domainmodel.persistence;

import java.sql.SQLException;
import java.util.Calendar;
import java.util.List;

import com.j256.ormlite.dao.BaseDaoImpl;
import com.j256.ormlite.dao.Dao;
import com.j256.ormlite.stmt.QueryBuilder;
import com.j256.ormlite.support.ConnectionSource;
import com.j256.ormlite.table.DatabaseTableConfig;
import com.j256.ormlite.table.TableUtils;

import de.zainodis.commons.LogCat;
import de.zainodis.commons.utils.DateTimeUtils;
import de.zainodis.kitchengnome.domainmodel.ItemList;
import de.zainodis.kitchengnome.domainmodel.ListItem;
import de.zainodis.kitchengnome.domainmodel.ListType;

/**
 * Handles persistence-related tasks for {@link ListItem}s.
 * 
 * @author fzarrai
 * 
 */
public interface IItemListDao extends Dao<ItemList, Long> {

	public static final String DATE_TIME_FORMAT = "yyyyMMddHHmmss";

	boolean save(ItemList list, DatabaseManager manager);

	boolean remove(ItemList list);

	/**
	 * 
	 * @param type
	 *           the type of the list.
	 * @return The last edited {@link ItemList} of the given type or null if none
	 *         was found.
	 * 
	 */
	ItemList getLastSaved(ListType type, DatabaseManager manager);

	/**
	 * 
	 * @param id
	 *           the id of the list.
	 * @return the list whose id matches the given id; or null if no match was
	 *         found.
	 * 
	 */
	ItemList getList(long id, DatabaseManager manager);

	/**
	 * Deletes all entries related to the given list as well as the list itself.
	 * 
	 * @param list
	 *           the list to delete.
	 * @return the number of deleted list entries.
	 */
	int deleteList(ItemList list, DatabaseManager manager);

	/**
	 * Deletes all {@link ItemList} and associated {@link ListItem}s.
	 * 
	 * @return the number of deleted lists.
	 */
	int clearAll(DatabaseManager manager);

	public class ItemListDao extends BaseDaoImpl<ItemList, Long> implements IItemListDao {

		private static final String TAG = "ItemListDao";

		public ItemListDao(ConnectionSource connectionSource) throws SQLException {
			super(connectionSource, ItemList.class);
		}

		public ItemListDao(ConnectionSource connectionSource, DatabaseTableConfig<ItemList> tableConfig)
				throws SQLException {
			super(connectionSource, tableConfig);
		}

		@Override
		public boolean save(ItemList list, DatabaseManager manager) {
			try {
				// Update last saved date-time
				list.setLastSaved(DateTimeUtils.format(Calendar.getInstance(), DATE_TIME_FORMAT));
				// Save the list attributes
				createOrUpdate(list);
				// Obtain dao class for list items
				IListItemDao itemDao = manager.getListEntryDao();

				for (ListItem item : list.getItems()) {
					// Update item's owner and...
					item.setOwnerId(list.getId());
					// ... save the item
					itemDao.saveItem(item);
				}

			} catch (SQLException e) {
				LogCat.e(TAG, "Failed to save list", e);
				return false;
			}
			return true;
		}

		@Override
		public boolean remove(ItemList list) {
			try {
				// Delete the given list
				delete(list);
			} catch (SQLException e) {
				LogCat.e(TAG, "Failed to delete list", e);
				return false;
			}
			return true;
		}

		@Override
		public ItemList getLastSaved(ListType type, DatabaseManager manager) {
			ItemList result = null;

			QueryBuilder<ItemList, Long> builder = queryBuilder();
			// Find the last-edited list
			builder.orderBy(ItemList.LAST_SAVED_FIELD, false);
			builder.limit(1L);
			try {
				// Filter by list type
				builder.where().eq(ItemList.TYPE_FIELD, type);
				List<ItemList> queryResult = query(builder.prepare());
				if (queryResult != null && queryResult.size() > 0) {
					result = queryResult.get(0);
					// Load related list items
					result.setItems(manager.getListEntryDao().getItems(result));
				}
			} catch (SQLException e) {
				LogCat.e(TAG, "Failed to query for last saved list of type " + type.toString(), e);
			}
			return result;
		}

		@Override
		public int deleteList(ItemList list, DatabaseManager manager) {
			int deleteCount = 0;
			try {
				delete(list);
				// Now delete all related entries
				deleteCount = manager.getListEntryDao().deleteItems(list);

			} catch (SQLException e) {
				LogCat.e(TAG, "Failed to clear list.", e);
			}
			return deleteCount;
		}

		@Override
		public int clearAll(DatabaseManager manager) {
			int deleteCount = 0;
			try {
				deleteCount = TableUtils.clearTable(connectionSource, ItemList.class);
				// Now delete all related entries
				manager.getListEntryDao().clearAll();

			} catch (SQLException e) {
				LogCat.e(TAG, "Failed to clear list.", e);
			}
			return deleteCount;
		}

		@Override
		public ItemList getList(long id, DatabaseManager manager) {
			ItemList result = null;
			try {
				result = queryForId(id);
				if (result != null) {
					// Load items for the found list
					result.setItems(manager.getListEntryDao().getItems(result));
				}

			} catch (SQLException e) {
				LogCat.e(TAG, "Failed to get list with id " + id, e);
			}
			return result;
		}
	}
}
